package org.spbsu.apco.server.scheduler;

import org.spbsu.apco.common.task.core.Ticket;

import java.util.*;

/**
 * User: Anton Ovchinnikov
 * Date: 1/10/13
 * Time: 4:38 PM
 */
public abstract class BaseMinScheduler extends BaseScheduler {

    protected final Map<String, Queue<Ticket>> clientTaskQueues = new HashMap<String, Queue<Ticket>>();

    protected double[][] c;

    @Override
    protected Ticket getTicketFor(String clientId) {
        // check if client is familiar
        if (!clientTaskQueues.containsKey(clientId)) {
            clientTaskQueues.put(clientId, new LinkedList<Ticket>());
            reschedule();
        }

        final Queue<Ticket> tickets = clientTaskQueues.get(clientId);
        return tickets.isEmpty() ? null : tickets.poll();
    }

    @Override
    protected void onReorganized() {
        reschedule();
    }

    protected void clearClientQueues() {
        for (String clientId : clientTaskQueues.keySet()) {
            clientTaskQueues.get(clientId).clear();
        }
    }

    protected void updateMatrix(Collection<Ticket> ticketList) {
        int i = 0;
        Set<String> allClients = clientTaskQueues.keySet();
        ArrayList<String> clients = new ArrayList<String>(allClients);
        int nClients = allClients.size();
        for (Ticket ticket : ticketList) {
            for (int j = 0; j < nClients; j++) {
                String clId = clients.get(j);
                int taskDuration = ticketDurationPredictor.predictDuration(ticket, clId);
                double readyTime = estimateReadyTime(clId);
                c[i][j] = taskDuration + readyTime;
            }
            i++;
        }
    }

    protected double estimateReadyTime(String clientId) {
        Queue<Ticket> clientTaskQueue = clientTaskQueues.get(clientId);
        double readyTime = 0;
        for (Ticket ticket : clientTaskQueue) {
            readyTime += ticketDurationPredictor.predictDuration(ticket, clientId);
        }
        return readyTime;
    }

    protected abstract void reschedule();
}
